package com.zhongtf.utils;

import io.github.novacrypto.bip32.ExtendedPrivateKey;
import io.github.novacrypto.bip32.ExtendedPublicKey;
import io.github.novacrypto.bip32.networks.Bitcoin;
import io.github.novacrypto.bip39.MnemonicGenerator;
import io.github.novacrypto.bip39.SeedCalculator;
import io.github.novacrypto.bip39.Words;
import io.github.novacrypto.bip39.wordlists.English;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.HDKeyDerivation;
import org.bitcoinj.params.MainNetParams;
import org.web3j.crypto.Keys;
import java.security.SecureRandom;

public  class BipUtils {
    /** 测试链可以用TestNet3Params */
    private static final MainNetParams mainnetParams = new MainNetParams();
    private static String mnemonics ="purity tunnel grid error scout long fruit false embody caught skin gate";
    /** 获取助记词，助记词12个英文单词,可以根据助记词可以得到种子 seed*/
    public static String generateMnemonics() {
        StringBuilder sb = new StringBuilder();
        byte[] entropy = new byte[Words.TWELVE.byteLength()];
        new SecureRandom().nextBytes(entropy);
        new MnemonicGenerator(English.INSTANCE)
                .createMnemonic(entropy, sb::append);
        return sb.toString();
    }
    /** 根据助记词得到种子*/
    public static ExtendedPrivateKey  getRootKey() {
        ExtendedPrivateKey rootKey = ExtendedPrivateKey.fromSeed(new SeedCalculator().calculateSeed(mnemonics, ""), Bitcoin.MAIN_NET);
        String rootKeyExtendedBase58 = rootKey.extendedBase58();
        System.out.println("rootKeyExtendedBase58:" + rootKeyExtendedBase58);
        return rootKey;
    }
    /** 1.用种子得到获得root_key对象
     *  2.根据root_key对象获得派生路径为 m/44'/60'/1'/* 的私钥对象,* 为数字，对应企业序号
     */
    public static ExtendedPrivateKey  getPriKey(int addressIndex) {
        ExtendedPrivateKey rootKey =getRootKey();
        ExtendedPrivateKey priKey = rootKey.derive("m/44'/60'/1'/"+addressIndex);
        return  priKey;
    }
    /**
     * 1.派生路径为 m/44'/60'/1'/* 的私钥对象转Base58字符串xprv
     * 2. xprv 扩展私钥 ，交易所保管
     * */
    public static String  getPriKeyExtendedBase58(int addressIndex) {
        ExtendedPrivateKey priKey = getPriKey(addressIndex);
        String priKeyExtendedBase58 = priKey.extendedBase58();
        System.out.println("派生路径为m/44'/60'/1'/*对应的私钥Base58字符串，xprv:" + priKeyExtendedBase58);
        return  priKeyExtendedBase58;
    }

    public static ExtendedPrivateKey  deserializePrikey(String priKeyExtendedBase58) {
        ExtendedPrivateKey priKey = ExtendedPrivateKey.deserializer().deserialize(priKeyExtendedBase58);
        return priKey;
    }

    /** 根据派生路径为 m/44'/60'/1'/* 的私钥对象获取对应的公钥*/
    public static ExtendedPublicKey  getPubKey(int addressIndex) {
        ExtendedPrivateKey priKey = getPriKey(addressIndex);
        ExtendedPublicKey pubKey = priKey.neuter();
        return  pubKey;
    }
    /**
     * 1.根据派生路径为 m/44'/60'/1'/* 的私钥对象获取得到对应的公钥，转Base58字符串xpub
     * 2.xpub 扩展公钥 ，企业保管
     * */
    public static String  getPubKeyExtendedBase58(int addressIndex) {
        ExtendedPublicKey pubKey = getPubKey(addressIndex);
        String pubKeyExtendedBase58 = pubKey.extendedBase58();
        System.out.println("派生路径为m/44'/60'/1'/*对应的公钥Base58字符串，xpub:" + pubKeyExtendedBase58);
        return  pubKeyExtendedBase58;
    }
    /** 根据派生路径为 m/44'/60'/1'/* 的私钥对象获取对应的公钥*/
    public static ExtendedPublicKey  getPubKeyByPrivKey(ExtendedPrivateKey priKey) {
        ExtendedPublicKey pubKey = priKey.neuter();
        return  pubKey;
    }
    public static String  getPubKeyExtendedBase58(ExtendedPublicKey pubKey) {
        String pubKeyExtendedBase58 = pubKey.extendedBase58();
        System.out.println("派生路径为m/44'/60'/1'/*对应的公钥Base58字符串，xpub:" + pubKeyExtendedBase58);
        return  pubKeyExtendedBase58;
    }
    public static ExtendedPublicKey  deserializePubkey(String pubKeyExtendedBase58) {
        ExtendedPublicKey pubKey = ExtendedPublicKey.deserializer().deserialize(pubKeyExtendedBase58);
        return pubKey;
    }
    /**
     * 1.根据派生路径为的私钥对象获取对应的子公钥对象，并转Base58字符串 ,比如 m/44'/60'/1'/0 的子私钥为  m/44'/60'/1'/0/*对应的私钥
     * 2.*对应每张票的票号
     * */
    public static String  getChildPubKeyByPriKey(ExtendedPrivateKey priKey,int addressIndex) {
        ExtendedPublicKey  childpubKey = priKey.cKDpub(addressIndex);
        String childpubKeyExtendedBase58 = childpubKey.extendedBase58();
        System.out.println("childpubKeyExtendedBase58:" + childpubKeyExtendedBase58);
        return  childpubKeyExtendedBase58;
    }

    /**
     * 1.根据派生路径的公钥对象获得对应的子公钥对象，并转Base58字符串 ，比如 m/44'/60'/1'/0 的子私钥为  m/44'/60'/1'/0/*对应的私钥
     * 2.*对应每张票的票号
     * */
    public static String  getChildPubKeyByPubKey(ExtendedPublicKey pubKey,int addressIndex) {
        ExtendedPublicKey  childpubKey = pubKey.cKDpub(addressIndex);
        String childpubKeyExtendedBase58 = childpubKey.extendedBase58();
        System.out.println("childpubKeyExtendedBase58:" + childpubKeyExtendedBase58);
        return  childpubKeyExtendedBase58;
    }
    /**
     * 用公钥生成ETH格式的地址
     * */
    public static String getEthAddress(int addressIndex, String pubKey) {
        DeterministicKey parentDK = DeterministicKey.deserializeB58(pubKey, mainnetParams);
        DeterministicKey childDK = HDKeyDerivation.deriveChildKey(parentDK, addressIndex);
        ECKey uncompressedChildKey = childDK.decompress();
        //以太坊需要把前缀去掉（0x04前缀表示未压缩）
        String hexK = uncompressedChildKey.getPublicKeyAsHex().substring(2);
        String addr = Keys.getAddress(hexK);
        String addrrss =Keys.toChecksumAddress(addr);
        System.out.println("address:" + addrrss);
        return addrrss;
    }

    public static void setMnemonics(String mnemonics) {
        BipUtils.mnemonics = mnemonics;
    }
    public static void main(String[] args) throws Exception {
        //助记词可以根据generateMnemonics()生成
        mnemonics="purity tunnel grid error scout long fruit false embody caught skin gate";
        //交易所保存私钥xpri，addressIndex 表示企业票的序号为，派生路径为m/44'/60'/1'/addressIndex，xprv:xprvA1wzUVhL969bgvQc2TKnoajUSPseKUda6DXGESEmA7QsA38GU8MGgbEERT2BQ9Jq2jZotsicGnzUHfhVNUhvRRo3nqxNb7dxjpABmozpyT5
        String priKeyExtendedBase58=BipUtils.getPriKeyExtendedBase58(0);
        //企业保存公钥xpub，addressIndex 表示企业票的序号为，派生路径为m/44'/60'/1'/addressIndex,
        //addressIndex=0时，xpub为 xpub6EwLt1EDyThtuQV58UroAigCzRi8iwMRTSSs2peNiSwr2qTR1ffXEPYiGhMJ3pwSx8RKfaABjGhsu9raX27shVVzeDkZSRiz3JFhPCm6Czf
        String pubKeyExtendedBase58=BipUtils.getPubKeyExtendedBase58(0);

        //由派生路径为m/44'/60'/1'/0的公钥获取地址m/44'/60'/1'/0/1的以太坊地址
        String address=getEthAddress(1,pubKeyExtendedBase58);

        //由私钥字符串priKeyExtendedBase58获取私钥对象
        ExtendedPrivateKey priKey= BipUtils.deserializePrikey(priKeyExtendedBase58);
        //由私钥对象得到相应的公钥对象
        ExtendedPublicKey  pubkey =getPubKeyByPrivKey(priKey);
        //公钥对象转换为公钥字符串
        pubKeyExtendedBase58= getPubKeyExtendedBase58(pubkey);
    }

}

